package com.library.service;

import com.library.dto.ReservationDTO;
import com.library.entity.Book;
import com.library.entity.Reservation;
import com.library.entity.User;
import com.library.exception.BusinessException;
import com.library.exception.NotFoundException;
import com.library.repository.BookRepository;
import com.library.repository.ReservationRepository;
import com.library.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 预约服务类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReservationService {
    private final ReservationRepository reservationRepository;
    private final BookRepository bookRepository;
    private final UserRepository userRepository;
    private final NotificationService notificationService;

    /**
     * 预约图书（库存为0时）
     */
    @Transactional
    public void reserveBook(Long userId, Long bookId) {
        // 检查用户是否存在
        User user = userRepository.findById(userId)
                .orElseThrow(() -> new NotFoundException("用户不存在"));

        // 检查图书是否存在
        Book book = bookRepository.findById(bookId)
                .orElseThrow(() -> new NotFoundException("图书不存在"));

        // 检查是否已有库存（有库存时不能预约）
        if (book.getStock() != null && book.getStock() > 0) {
            throw new BusinessException("图书有库存，请直接借阅");
        }

        // 检查是否已预约
        if (reservationRepository.findByUserIdAndBookId(userId, bookId).isPresent()) {
            throw new BusinessException("您已预约该图书");
        }

        // 创建预约记录
        Reservation reservation = new Reservation();
        reservation.setUser(user);
        reservation.setBook(book);
        reservation.setStatus("pending");
        reservationRepository.save(reservation);
        log.info("预约图书成功: 用户ID={}, 图书ID={}", userId, bookId);
    }

    /**
     * 取消预约
     */
    @Transactional
    public void cancelReservation(Long userId, Long reservationId) {
        Reservation reservation = reservationRepository.findById(reservationId)
                .orElseThrow(() -> new NotFoundException("预约记录不存在"));

        // 检查权限
        if (!reservation.getUser().getId().equals(userId)) {
            throw new BusinessException("无权操作此预约");
        }

        // 检查状态
        if (!"pending".equals(reservation.getStatus()) && !"available".equals(reservation.getStatus())) {
            throw new BusinessException("该预约不能取消");
        }

        reservation.setStatus("cancelled");
        reservationRepository.save(reservation);
        log.info("取消预约成功: 用户ID={}, 预约ID={}", userId, reservationId);
    }

    /**
     * 获取预约列表
     */
    public List<ReservationDTO> getReservations(Long userId, boolean isAdmin) {
        List<Reservation> reservations;
        if (isAdmin) {
            reservations = reservationRepository.findByStatusOrderByCreatedAtAsc("pending");
        } else {
            reservations = reservationRepository.findByUserIdOrderByCreatedAtDesc(userId);
        }
        return reservations.stream()
                .map(this::convertToDTO)
                .collect(Collectors.toList());
    }

    /**
     * 通知预约用户（当图书归还时调用）
     */
    @Transactional
    public void notifyAvailableReservations(Long bookId) {
        List<Reservation> reservations = reservationRepository.findByBookIdOrderByCreatedAtAsc(bookId);
        for (Reservation reservation : reservations) {
            if ("pending".equals(reservation.getStatus())) {
                reservation.setStatus("available");
                reservation.setNotifiedAt(LocalDateTime.now());
                reservationRepository.save(reservation);

                // 发送通知
                notificationService.createNotification(
                        reservation.getUser().getId(),
                        "预约图书可借阅",
                        "您预约的图书《" + reservation.getBook().getTitle() + "》现在可以借阅了",
                        "reservation_available"
                );
            }
        }
    }

    /**
     * 将Reservation实体转换为DTO
     */
    private ReservationDTO convertToDTO(Reservation reservation) {
        ReservationDTO dto = new ReservationDTO();
        dto.setId(reservation.getId());
        dto.setUserId(reservation.getUser().getId());
        dto.setUsername(reservation.getUser().getUsername());
        dto.setBookId(reservation.getBook().getId());
        dto.setTitle(reservation.getBook().getTitle());
        dto.setAuthor(reservation.getBook().getAuthor());
        dto.setIsbn(reservation.getBook().getIsbn());
        dto.setStatus(reservation.getStatus());
        dto.setCreatedAt(reservation.getCreatedAt());
        dto.setNotifiedAt(reservation.getNotifiedAt());
        return dto;
    }
}

